#include "tty.h"
#include "kernel.h"
#include "mm.h"

// 这个地址为什么是这样的呢？
// 实际上是因为64位的机器我们实际用的是48位地址，但是高于48位的地址必须用1填充
// 所以实际上这个地址就是0x800000000000
// 这个又是什么呢？
// 见oskernel\init\main.c，我们用的实际上是9 9 9 21分页，
// 也就是说，我们的第一层页目录有512个页表项，每一个又有512个页表项，每一个又有512个页表项，每一个又有512个页表项，然后最后一层代表2m的页。
// 对于0x800000000000，我们右移39位后得到0x100，即十进制256，这一项被修改成了0x9000，也就是说第一个页表项
// 所以，指向了低地址
// 执行kernel64_main的前两行代码后，有0x0和0x800000000000都是指向第一个页表项的
 int64 kernel_space_base_addr = 0xffff800000000000;
//#define PDT_INDEX 0x100

//static int64 get_high_virtual_addr(int64 addr)
//{
//    // 这里有个坑，如果不加括号，就会把0xffff当成int，然后左移48位后再转成int64，就会变成0
//    int64 kernel_space_base_addr = ((int64)0xffff << 48) | ((int64)PDT_INDEX << 39) | ((int64) 0 << 30) | ((int64)0 << 21);
//    return addr | kernel_space_base_addr;
//}

static void write_datas(char* p)
{
    for (int i = 0; i < 10; i++)
    {
        p[i] = i + '0';
    }
}

static void show_datas(char* p)
{
    printk("the data at %x is:%s\n", p, p);
}

void start_kernel(void)
{
    // 结果还是一样的：
    //  a00000
    //  a01000
    //  a02000
//    console_init();
//    // 有问题，运行出来多了一些东西
//    // printk("Hello, %10s", "zhuguoyin");
////    phy_memory_init();
//    print_check_memory_info();
//
//    char* p = get_free_page();
//    printk("%x\n", p);
//
//    // write_datas(p);
//
////    show_datas(p);
//
////    char *p1 = kernel_space_base_addr + (int64) p;
////    show_datas(p1);
//
//    p = get_free_page();
//    printk("%x\n", p);
//
//    free_page(p);
//
//    p = get_free_page();
//    printk("%x\n", p);

    printk("hello:%s", "zhuguoyin");

    while (true) {
        asm volatile("hlt;");
    }
}

static void run_in_high_virtual_addr()
{
    //   *(int*)(0x8000 + PDT_INDEX * 8) = 0x9000 | 3;
    //   *(int*)(0x8000 + PDT_INDEX * 8 + 4) = 0;
    //   int64 addr = get_high_virtual_addr((int64) start_kernel);
    *(int*) (0x8000 + 256 * 8) = 0x9000 | 3;
    *(int*) (0x8000 + 256 * 8 + 4) = 0;
    int64 addr = kernel_space_base_addr + (int64) start_kernel;
    asm volatile("jmp %0;"::"r"(addr));
}

void kernel64_main(void)
{

/**
 // 以下代码运行出来的结果是
 a00000
 a01000
 a02000

 放到虚拟地址里再看看呢
    console_init();
    // 有问题，运行出来多了一些东西
    // printk("Hello, %10s", "zhuguoyin");
    phy_memory_init();
    print_check_memory_info();

    void *p = get_free_page();
    printk("get_free_page: %x\n", p);

    p = get_free_page();
    printk("get_free_page1: %x\n", p);

    p = get_free_page();
    printk("get_free_page2: %x\n", p);
    */

    console_init();
    /**** 把下面这段代码放到start_kernel里面就会报错，原因是什么呢？ *****/
    phy_memory_init();
    print_check_memory_info();
    void *p = get_free_page();
    printk("get_free_page: %x\n", p);

    free_page(p);

    p = get_free_page();
    printk("get_free_page1: %x\n", p);

    p = get_free_page();
    printk("get_free_page2: %x\n", p);
    /**** 把上面这段代码放到start_kernel里面就会报错，原因是什么呢？ *****/
    run_in_high_virtual_addr();
}